Introduction

The objective of this second assignment is to explore the differentially expressed genes from the cleaned and normalized data in assignmnent one. Then rank the thresholded over-representation analysis to highlight the top terms / dominant themes in the top set of genes. Lastly, compare my result with the original literature and find some other supports as well for my result if possible. I make some changes to my assignment one and stored the file as “ammended_A1.Rmd” and imported it here. I will demonstrate briefly what I have changed in general workflow in A1. My summary of the paper can be found at my journal or in A1.

(Ritchie et al. 2015) (Robinson, McCarthy, and Smyth 2010) (Rainer 2017) (Xie 2020) (Gu, Eils, and Schlesner 2016) (Gu et al. 2014) (Kolberg and Raudvere 2019)

A1

My data is from GSE84054 (Goh et al. 2017)

What I have changed in A1: I decided to leave the genes that have duplicated names because Ruth sugguested that they are a very small number compare to my total number of genes, ~1%. So I deleted many steps in A1, and made the cleaning step clearer by showing boxplots, density plots and MDS plots in each cleaning step.

  1. Boxplot - prefiltered
  1. Density Plot - prefiltered
  1. MDS plot - prefiltered
  1. Boxplot - filtered
  1. Density plot - filtered
  1. MDS plot - filtered

A2

Load data

Loaded my normalized data from A1.

normalized_count_data <- read.table(file="GSE84054_normalized_count.txt")
kable(normalized_count_data[1:5, 1:5], type="html")
GENEID SYMBOL RHB037 RHB038 RHB041
ENSG00000000003 ENSG00000000003 TSPAN6 79.809196 63.375225 37.719858
ENSG00000000419 ENSG00000000419 DPM1 36.461054 38.451386 49.614654
ENSG00000000457 ENSG00000000457 SCYL3 12.060195 12.077110 6.329049
ENSG00000000460 ENSG00000000460 C1orf112 6.762435 4.972927 3.848316
ENSG00000000938 ENSG00000000938 FGR 1.402348 3.966502 1.940060

Explore: Normalized

We need to explore the data again after normalization to ensure the normalized data reaches our expectations.

  1. boxplot - normalized
# After normalization
data2plot_after <- log2(normalized_count_data[,3:ncol(normalized_count_data)])
{boxplot(data2plot_after, xlab = "Samples", ylab = "log2 CPM", 
        las = 2, cex = 0.5, cex.lab = 0.5,
        cex.axis = 0.5, main = "Filtered and normalized RNASeq Samples")
abline(h = median(apply(data2plot_after, 2, median)), col = "green", lwd = 0.6, lty = "dashed")}

  1. density plot - normalized
counts_density <- apply(log2(normalized_count_data[,3:ncol(normalized_count_data)]), 2, density)
  #calculate the limits across all the samples
    xlim <- 0; ylim <- 0
    for (i in 1:length(counts_density)) {
      xlim <- range(c(xlim, counts_density[[i]]$x)); 
      ylim <- range(c(ylim, counts_density[[i]]$y))
    }
    cols <- rainbow(length(counts_density))
    ltys <- rep(1, length(counts_density))
    #plot the first density plot to initialize the plot
    plot(counts_density[[1]], xlim=xlim, ylim=ylim, type="n", 
         ylab="Smoothing density of log2-CPM",cex.lab = 0.85, 
         main = "Filtered and normalized RNASeq Samples distribution")
    #plot each line
    for (i in 1:length(counts_density)) lines(counts_density[[i]], col=cols[i], lty=ltys[i])
    legend("topright", colnames(data2plot), col=cols, lty=ltys, cex=0.75, 
           border ="blue",  text.col = "green4", merge = TRUE, bg = "gray90")

PART #1: differential expression

  1. Calculate p-values for each of the genes in your expression set. How many genes were significantly differentially expressed? What thresholds did you use and why?
  • There are 7464 genes that are below the p-value. The threshold I used is 0.05 because this is what the authors of the paper sugguested that they use.
  1. Multiple hypothesis testing - correct your p-values using a multiple hypothesis correction method. Which method did you use? And Why? How many genes passed correction?
  • I used FDR correction which is also what the authors of the paper specified. 5033 genes passed the correction. Both the p-value and the correction data are based on the edgeR package, not the limma package. I used the limma package up till the point of calculating differential expression like what is sugguested on the lecture notes.
  1. Show the amount of differentially expressed genes using an MA Plot or a Volcano plot. Highlight genes of interest.
  • I showed a volcano plot using my edgeR fitted data and highlighed the upregulated to be red and down regulated to be blue.
  1. Visualize your top hits using a heatmap. Do you conditions cluster together? Explain why or why not.
  • My data clustered perfectly according to their cell types which is what my model design based on. My interpretation for the graph would be that since the colors are opposite to each other in the two different cell types, it means that the genes that are upregulated in tumoursphere would be down regulated in primary tumour samples. The shows a great results that the upregulated genes can be potential biomarkers to track if tumoursphere is present or not.

STEP 1: Choice of factors in my model

  • I created the MDS by both using “cell_type” and “cell_type” and “patient”. The comparison between the two models is fairly clear: we should only depend on the factor “cell_type”, since there seems to be no correlation with each patient.
heatmap_matrix <- normalized_count_data[,3:ncol(normalized_count_data)]
rownames(heatmap_matrix) <- normalized_count_data$GENEID
colnames(heatmap_matrix) <- rownames(samples_filtered)

# MDS plot by "cell_type" in samples
plotMDS(heatmap_matrix, labels=rownames(samples_filtered), 
        col = c("darkgreen","blue")[factor(samples_filtered$cell_type)],
        main = "MDS plot depending on cell type")

pat_colors <- rainbow(12)
pat_colors <- unlist(lapply(pat_colors,FUN=function(x){rep(x,2)}))
# MDS plot by "cell_type" + "patients"in samples
plotMDS(heatmap_matrix, col = pat_colors,
        main = "MDS plot depending on both cell type and patients")

STEP 2: Define my model design

Based on the two models in part1, I decide to base my model only on “cell_type”

model_design <- model.matrix(~ samples$cell_type)
kable(model_design, type="html")
(Intercept) samples$cell_typeSphere
1 0
1 0
1 0
1 0
1 0
1 0
1 0
1 0
1 0
1 0
1 0
1 0
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1

STEP 3: Calculate p-value

There are 6988 genes that pass the p-value = 0.05 which is chosen based on the paper.

expressionMatrix <- as.matrix(normalized_count_data[,3:ncol(normalized_count_data)])
rownames(expressionMatrix) <- normalized_count_data$GENEID
colnames(expressionMatrix) <- colnames(normalized_count_data)[3:ncol(normalized_count_data)]
minimalSet <- ExpressionSet(assayData=expressionMatrix)

# fit
fit <- lmFit(minimalSet, model_design)

# Use Bayes
fit2 <- eBayes(fit,trend=TRUE)

# Correction: BH (recommended by the paper)
topfit <- topTable(fit2, coef=ncol(model_design),
                   adjust.method = "BH",
                   number = nrow(expressionMatrix))

# merge gene symbol to topfit table
output_hits <- merge(normalized_count_data[,1:2], topfit, by.y = 0, by.x = 1, all.y=TRUE)

#sorted by P-value
output_hits <- output_hits[order(output_hits$P.Value),]
kable(output_hits[1:5,],type="html")

# number of genes that pass threshold p-value = 0.05
length(which(output_hits$P.Value < 0.05)) # 6988
# number of genes that pass correction
length(which(output_hits$adj.P.Val < 0.05)) # 4062

STEP 4: Set up EdgeR object

d = DGEList(counts=filtered_data_matrix, group=samples$cell_type)
d <- estimateDisp(d, model_design_pat)

STEP 5: Test whether my data is suitable for edgeR - MeanVar plot

I have shown that my data is suitable for using edgeR for further analysis. The data follows the binomial distribution.

plotMeanVar(d, show.raw.vars = TRUE,                
            show.tagwise.vars=TRUE,                 
            show.ave.raw.vars = TRUE,                                                         
            NBline=TRUE,
            show.binned.common.disp.vars = TRUE,
            main = "Binomial distribution of my data")

STEP 6: Estimate dispersion - BCV plot

The individual dots represent each gene and the blue line is the overall trend line.

plotBCV(d,col.tagwise = "black",col.common = "red", 
        main = "BCV plot of RNA-seq data")

STEP 7: Genes pass threshold and FDR correction

I used Quasi-likelihood models to fit my data and used QLFTest to test for differential expression. The Quasi-likelihood compares two conditions (primary tumour and tumoursphere) and shows the up and down-regulated genes. The result below that are sorted by p-value. I also inspected the number of genes that satisty my threshold and correction. I choose to use FDR correction based on the paper as well(Goh et al. 2017) . There are 7467 genes pass the p-value = 0.05, and 5033 genes that pass the FDR correction.

fit <- glmQLFit(d, model_design)
qlf.sphere_vs_tumour <- glmQLFTest(fit, coef='samples$cell_typeSphere')
kable(topTags(qlf.sphere_vs_tumour), type="html")

# Get all the results
qlf_output_hits <- topTags(qlf.sphere_vs_tumour, 
                           sort.by = "PValue", 
                           n = nrow(normalized_count_data))

# Number of genes that pass the threshold p-value = 0.05
length(which(qlf_output_hits$table$PValue < 0.05)) # 7467
# Number of genes that pass correction
length(which(qlf_output_hits$table$FDR < 0.05)) # 5033

STEP 8: Up and down-regulated genes

I determined the number of up-regulated genes by selecting every gene that does not pass my p-value: 0.05, and also have a positive log fold change. Down-regulated genes are selected in the same way with a negative log fold change. Stored these data for later enrichment analysis on gProfileR.

# number of genes that are up regulated
length(which(qlf_output_hits$table$PValue < 0.05 
             & qlf_output_hits$table$logFC > 0)) # 1897
# number of genes that are down regulated
length(which(qlf_output_hits$table$PValue < 0.05  
             & qlf_output_hits$table$logFC < 0)) # 5570
# Get those up and down-regulated genes
qlf_output_hits_withgn <- merge(expr_filtered[,1:2],qlf_output_hits, by.x=1, by.y = 0)

upregulated_genes <- qlf_output_hits_withgn$GENEID[which(qlf_output_hits$table$PValue < 0.05 
                                                         & qlf_output_hits$table$logFC > 0)]

downregulated_genes <-qlf_output_hits_withgn$GENEID[which(qlf_output_hits$table$PValue < 0.05 
                                                           & qlf_output_hits$table$logFC < 0)]


# store data - all differentially expressed
unreg_genes_copy <- data.frame(upregulated_genes)
downreg_genes_copy <- data.frame(downregulated_genes)
names(unreg_genes_copy) <- names(downreg_genes_copy)
all_de <- rbind(unreg_genes_copy, downreg_genes_copy)
colnames(all_de) <- "all_de"
write.table(x=all_de,
            file="all_expr_de_genes.txt",sep = "\t",
            row.names = FALSE,col.names = FALSE,quote = FALSE)

# up regulated
write.table(x=upregulated_genes,
            file="expr_upregulated_genes.txt",sep = "\t",
            row.names = FALSE,col.names = FALSE,quote = FALSE)

# down regulated
write.table(x=downregulated_genes,
            file="expr_downregulated_genes.txt",sep = "\t",
            row.names = FALSE,col.names = FALSE,quote = FALSE)

STEP 9: Show up and down-regulated genes

I have shown the up and down-regulated genes in a volcano plot by coloring them in red and blue, the code is from (Annick Moisan, n.d.)

volcanoData <- cbind(qlf_output_hits$table$logFC, -log10(qlf_output_hits$table$FDR))
colnames(volcanoData) <- c("logFC", "Pval")

up <- qlf_output_hits$table$FDR < 0.05 & qlf_output_hits$table$logFC > 0
point.col <- ifelse(up, "red", "black")
plot(volcanoData, pch = 16, col = point.col, cex = 0.5,
     main = "Up-regulated genes in RNA-seq data")

down <- qlf_output_hits$table$FDR < 0.05 & qlf_output_hits$table$logFC < 0
point.col <- ifelse(down, "blue", "black")
plot(volcanoData, pch = 16, col = point.col, cex = 0.5,
      main = "Down-regulated genes in RNA-seq data")

STEP 10: Test Differential expression - heatmap

To test the differential expression, I used the heatmap and it has shown a clear distinction between up and down regulated genes. There is a clear difference between the primary tumour samples and tumoursphere samples.(They are reversed.) The clustering is very obvious to show that differential expression exists.

top_hits <- rownames(qlf_output_hits$table)[output_hits$P.Value<0.05] 
heatmap_matrix_tophits <- t(scale(t(heatmap_matrix[which(rownames(heatmap_matrix) %in% top_hits),]))) 
heatmap_matrix_tophits <- heatmap_matrix_tophits[, c(grep(colnames(heatmap_matrix_tophits),pattern = "_P"), 
                                                    grep(colnames(heatmap_matrix_tophits),pattern = "_S"))]

if(min(heatmap_matrix_tophits) == 0){
    heatmap_col = colorRamp2(c( 0, max(heatmap_matrix_tophits)), 
                             c( "white", "red"))
    } else {
    heatmap_col = colorRamp2(c(min(heatmap_matrix_tophits), 0, max(heatmap_matrix_tophits)), c("blue", "white", "red"))
    }

current_heatmap <- Heatmap(as.matrix(heatmap_matrix_tophits),
                           cluster_rows = TRUE,
                           cluster_columns = FALSE,
                               show_row_dend = TRUE,
                               show_column_dend = FALSE,
                               col=heatmap_col,
                               show_column_names = TRUE, 
                               show_row_names = FALSE,
                               show_heatmap_legend = TRUE,)
current_heatmap

PART 2: Thresholded over-representation analysis

Introduction to PART 2:

  1. Which method did you choose and why?
  • I chose to use g:profiler because it shows me the top term names in KEGG, WP, GO and REAC, which is helpful for me when deciding what type of disease it is most likely to be.
  1. What annotation data did you use and why? What version of the annotation are you using?
  • GO biological process: releases/2019-07-01
  • KEGG: KEGG FTP Release 2019-09-30
  • Reactome: ensembl classes: 2019-10-2
  • WikiPathways: 20190910
  1. How many genesets were returned with what thresholds?
  • The threshold for all the queries: 0.05
  • 821 gene sets are returned for all the differentially expressed genes.
  • 60 gene sets are returned for up-regulated genes.
  • 1333 gene sets are returned for down-regulated genes.
  1. Run the analysis using the up-regulated set of genes, and the down-regulated set of genes separately. How do these results compare to using the whole list (i.e all differentially expressed genes together vs. the up-regulated and down regulated differentially expressed genes separately)?
  • The up-regulated gene sets are mostly cellular processes and metabolic processes.
  • The top terms for down-regulated gene sets are mostly signaling pathways and metabolic processes/
  • When running with both up and down-regulated genes, I found that most of them are dominated by the metabolic and cellular processes (up regulated top terms). Therefore, it convinces me the importance of the up-regulated genes in the cancer. And the result aligns with the paper that states the cancer is of subtype “basal”.
  • Below are my results for each up-regulated, down-regulated, and differentially expressed (both).

Up regulated genes

There were no REAC found. I used the gprofiler2’s function to query data and also attached the screenshots that I took on their website since the package does not show the number of gene sets each has found.

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/all_up.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/KEGG_up.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/WP_up.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/GO_up.png")

gpro_upregulated <- gprofiler2::gost(upregulated_genes, 
                                  organism = "hsapiens", 
                                  ordered_query = FALSE,
                                  multi_query = FALSE, 
                                  significant = TRUE, 
                                  exclude_iea = FALSE,
                                  measure_underrepresentation = FALSE, 
                                  evcodes = FALSE,
                                  user_threshold = 0.05, 
                                  correction_method = c("fdr"),
                                  domain_scope = c("annotated", "known", "custom", "custom_annotated"),
                                  custom_bg = NULL, 
                                  numeric_ns = "", 
                                  sources = c("GO:BP", "KEGG", "REAC", "WP"),
                                  as_short_link = FALSE)

gprofiler2::gostplot(gpro_upregulated, 
                     capped = TRUE, 
                     interactive = TRUE, 
                     pal = c(`GO:BP` = "#ff9900", 
                             KEGG = "#dd4477",
                             REAC = "#3366cc", 
                             WP = "#0099c6"))

Down regulated genes

The some analysis is apply to down regulated

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/all_down.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/KEGG_down.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/WP_down.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/GO_down.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/REAC_down.png")

gpro_downregulated <- gprofiler2::gost(downregulated_genes, 
                                  organism = "hsapiens", 
                                  ordered_query = FALSE,
                                  multi_query = FALSE, 
                                  significant = TRUE, 
                                  exclude_iea = FALSE,
                                  measure_underrepresentation = FALSE, 
                                  evcodes = FALSE,
                                  user_threshold = 0.05, 
                                  correction_method = c("fdr"),
                                  domain_scope = c("annotated", "known", "custom", "custom_annotated"),
                                  custom_bg = NULL, 
                                  numeric_ns = "", 
                                  sources = c("GO:BP", "KEGG", "REAC", "WP"),
                                  as_short_link = FALSE)
gprofiler2::gostplot(gpro_downregulated, 
                     capped = TRUE, 
                     interactive = TRUE, 
                     pal = c(`GO:BP` = "#ff9900", 
                             KEGG = "#dd4477",
                             REAC = "#3366cc", 
                             WP = "#0099c6"))

All differentially expressed genes

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/all_DE.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/KEGG_DE.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/WP_DE.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/GO_DE.png")

knitr::include_graphics("/Users/helending/Documents/BCB420/pics/REAC_DE.png")

all_de <- read.table("all_expr_de_genes.txt")
gpro_all_de <- gprofiler2::gost(all_de[,1],
                                  organism = "hsapiens", 
                                  ordered_query = FALSE,
                                  multi_query = FALSE, 
                                  significant = TRUE, 
                                  exclude_iea = FALSE,
                                  measure_underrepresentation = FALSE, 
                                  evcodes = FALSE,
                                  user_threshold = 0.05, 
                                  correction_method = c("fdr"),
                                  domain_scope = c("annotated", "known", "custom", "custom_annotated"),
                                  custom_bg = NULL, 
                                  numeric_ns = "", 
                                  sources = c("GO:BP", "KEGG", "REAC", "WP"),
                                  as_short_link = FALSE)
gprofiler2::gostplot(gpro_all_de, 
                     capped = TRUE, 
                     interactive = TRUE, 
                     pal = c(`GO:BP` = "#ff9900", 
                             KEGG = "#dd4477",
                             REAC = "#3366cc", 
                             WP = "#0099c6"))

Interpretation questions

  1. Do the over-representation results support conclusions or mechanism discussed in the original paper?
upregulated_genes_sym <- qlf_output_hits_withgn$SYMBOL[which(qlf_output_hits$table$PValue < 0.05 
                                                         & qlf_output_hits$table$logFC > 1)]

length(upregulated_genes_sym) # 1312
upregulated_genes_sym[grep(pattern="ALDH",upregulated_genes_sym)]
# ALDH2, ALDH8A1, ALDH1L2 -> confirmed!
  1. Evidence that support and how they support your results.

References

Annick Moisan, Nathalie Villa-Vialaneix, Ignacio Gonzales. n.d. “Practical Statistical Analysis of Rna-Seq Data - edgeR - Tomato Data.”

Goh, Jian Yuan, Min Feng, Wenyu Wang, Gokce Oguz, Siti Maryam JM Yatim, Puay Leng Lee, Yi Bao, et al. 2017. “Chromosome 1q21.3 Amplification Is a Trackable Biomarker and Actionable Target for Breast Cancer Recurrence.” Nature Medicine 23 (11). Nature Publishing Group: 1319.

Gu, Zuguang, Roland Eils, and Matthias Schlesner. 2016. “Complex Heatmaps Reveal Patterns and Correlations in Multidimensional Genomic Data.” Bioinformatics.

Gu, Zuguang, Lei Gu, Roland Eils, Matthias Schlesner, and Benedikt Brors. 2014. “Circlize Implements and Enhances Circular Visualization in R.” Bioinformatics 30 (19): 2811–2.

Kolberg, Liis, and Uku Raudvere. 2019. Gprofiler2: Interface to the ’G:Profiler’ Toolset. https://CRAN.R-project.org/package=gprofiler2.

Rainer, Johannes. 2017. EnsDb.Hsapiens.v75: Ensembl Based Annotation Package.

Ritchie, Matthew E, Belinda Phipson, Di Wu, Yifang Hu, Charity W Law, Wei Shi, and Gordon K Smyth. 2015. “limma Powers Differential Expression Analyses for RNA-Sequencing and Microarray Studies.” Nucleic Acids Research 43 (7): e47. https://doi.org/10.1093/nar/gkv007.

Robinson, M D, D J McCarthy, and G K Smyth. 2010. “EdgeR: A Bioconductor Package for Differential Expression Analysis of Digital Gene Expression Data.” Bioinformatics 26 (1): 139–40. https://doi.org/10.1093/bioinformatics/btp616.

Vasiliou, Vasilis, and Daniel W Nebert. 2005. “Analysis and Update of the Human Aldehyde Dehydrogenase (Aldh) Gene Family.” Human Genomics 2 (2). BioMed Central: 138.

Vassalli, Giuseppe. 2019. “Aldehyde Dehydrogenases: Not Just Markers, but Functional Regulators of Stem Cells.” Stem Cells International 2019. Hindawi.

Xie, Yihui. 2020. Knitr: A General-Purpose Package for Dynamic Report Generation in R. https://yihui.org/knitr/.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKYXV0aG9yOiAiWWluaW5nIERpbmciCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwpiaWJsaW9ncmFwaHk6IEEyLmJpYgotLS0KCgoKIyBJbnRyb2R1Y3Rpb24KVGhlIG9iamVjdGl2ZSBvZiB0aGlzIHNlY29uZCBhc3NpZ25tZW50IGlzIHRvIGV4cGxvcmUgdGhlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBmcm9tIHRoZSBjbGVhbmVkIGFuZCBub3JtYWxpemVkIGRhdGEgaW4gYXNzaWdubW5lbnQgb25lLiBUaGVuIHJhbmsgdGhlIHRocmVzaG9sZGVkIG92ZXItcmVwcmVzZW50YXRpb24gYW5hbHlzaXMgdG8gaGlnaGxpZ2h0IHRoZSB0b3AgdGVybXMgLyBkb21pbmFudCB0aGVtZXMgaW4gdGhlIHRvcCBzZXQgb2YgZ2VuZXMuIExhc3RseSwgY29tcGFyZSBteSByZXN1bHQgd2l0aCB0aGUgb3JpZ2luYWwgbGl0ZXJhdHVyZSBhbmQgZmluZCBzb21lIG90aGVyIHN1cHBvcnRzIGFzIHdlbGwgZm9yIG15IHJlc3VsdCBpZiBwb3NzaWJsZS4gSSBtYWtlIHNvbWUgY2hhbmdlcyB0byBteSBhc3NpZ25tZW50IG9uZSBhbmQgc3RvcmVkIHRoZSBmaWxlIGFzICJhbW1lbmRlZF9BMS5SbWQiIGFuZCBpbXBvcnRlZCBpdCBoZXJlLiBJIHdpbGwgZGVtb25zdHJhdGUgYnJpZWZseSB3aGF0IEkgaGF2ZSBjaGFuZ2VkIGluIGdlbmVyYWwgd29ya2Zsb3cgaW4gQTEuIE15IHN1bW1hcnkgb2YgdGhlIHBhcGVyIGNhbiBiZSBmb3VuZCBhdCBbbXkgam91cm5hbF0oaHR0cHM6Ly9naXRodWIuY29tL2JjYjQyMC0yMDIwL3N0dWRlbnRfaGVsZW4zMDcvd2lraS9hMSkgb3IgaW4gQTEuCgpbQGxpbW1hXQpbQFJvYmluc29uOjIwMTA6QmlvaW5mb3JtYXRpY3M6MTk5MTAzMDhdCltARW5zRGIuSHNhcGllbnMudjc1XQpbQGtuaXRyXQpbQGhlYXRtYXBdCltAY2lyY2xpemVdCltAZ3Byb2ZpbGVyMl0KYGBge3Igc2V0dXAsIHJlc3VsdHM9ImhpZGUiLCBpbmNsdWRlID0gRkFMU0V9CmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpCgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoImxpbW1hIiwgcXVpZXRseSA9IFRSVUUpKQogICAgQmlvY01hbmFnZXI6Omluc3RhbGwoImxpbW1hIikKCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQ29tcGxleEhlYXRtYXAiLCBxdWlldGx5ID0gVFJVRSkpCiAgICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiQ29tcGxleEhlYXRtYXAiKQoKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJlZGdlUiIsIHF1aWV0bHkgPSBUUlVFKSkKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJlZGdlUiIpCgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIkVuc0RiLkhzYXBpZW5zLnY3NSIsIHF1aWV0bHkgPSBUUlVFKSkKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJFbnNEYi5Ic2FwaWVucy52NzUiKQoKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJrbml0ciIsIHF1aWV0bHkgPSBUUlVFKSkKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJrbml0ciIpCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiZ3Byb2ZpbGVyMiIsIHF1aWV0bHkgPSBUUlVFKSkKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJncHJvZmlsZXIyIikKCmxpYnJhcnkobGltbWEpCmxpYnJhcnkoZWRnZVIpCmxpYnJhcnkoRW5zRGIuSHNhcGllbnMudjc1KQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KGNpcmNsaXplKQpsaWJyYXJ5KGdwcm9maWxlcjIpCgpgYGAKCmBgYHtyIGNoaWxkPSdhbW1lbmRlZF9BMS5SbWQnLCBpbmNsdWRlPUZBTFNFLCBldmFsPVRSVUV9CmBgYAojIEEyCiMjIExvYWQgZGF0YQpMb2FkZWQgbXkgbm9ybWFsaXplZCBkYXRhIGZyb20gQTEuCmBgYHtyIGxvYWQgbm9ybSBkYXRhfQpub3JtYWxpemVkX2NvdW50X2RhdGEgPC0gcmVhZC50YWJsZShmaWxlPSJHU0U4NDA1NF9ub3JtYWxpemVkX2NvdW50LnR4dCIpCmthYmxlKG5vcm1hbGl6ZWRfY291bnRfZGF0YVsxOjUsIDE6NV0sIHR5cGU9Imh0bWwiKQpgYGAKIyMgRXhwbG9yZTogTm9ybWFsaXplZCAKCldlIG5lZWQgdG8gZXhwbG9yZSB0aGUgZGF0YSBhZ2FpbiBhZnRlciBub3JtYWxpemF0aW9uIHRvIGVuc3VyZSB0aGUgbm9ybWFsaXplZCBkYXRhIHJlYWNoZXMgb3VyIGV4cGVjdGF0aW9ucy4KCjEuIGJveHBsb3QgLSBub3JtYWxpemVkCmBgYHtyIGJveHBsb3Rfbm9ybWFsaXplZCwgd2FybmluZz1GQUxTRX0KIyBBZnRlciBub3JtYWxpemF0aW9uCmRhdGEycGxvdF9hZnRlciA8LSBsb2cyKG5vcm1hbGl6ZWRfY291bnRfZGF0YVssMzpuY29sKG5vcm1hbGl6ZWRfY291bnRfZGF0YSldKQp7Ym94cGxvdChkYXRhMnBsb3RfYWZ0ZXIsIHhsYWIgPSAiU2FtcGxlcyIsIHlsYWIgPSAibG9nMiBDUE0iLCAKICAgICAgICBsYXMgPSAyLCBjZXggPSAwLjUsIGNleC5sYWIgPSAwLjUsCiAgICAgICAgY2V4LmF4aXMgPSAwLjUsIG1haW4gPSAiRmlsdGVyZWQgYW5kIG5vcm1hbGl6ZWQgUk5BU2VxIFNhbXBsZXMiKQphYmxpbmUoaCA9IG1lZGlhbihhcHBseShkYXRhMnBsb3RfYWZ0ZXIsIDIsIG1lZGlhbikpLCBjb2wgPSAiZ3JlZW4iLCBsd2QgPSAwLjYsIGx0eSA9ICJkYXNoZWQiKX0KYGBgCgoyLiBkZW5zaXR5IHBsb3QgLSBub3JtYWxpemVkCmBgYHtyIGRlbnNpdHlfbm9ybWFsaXplZH0KY291bnRzX2RlbnNpdHkgPC0gYXBwbHkobG9nMihub3JtYWxpemVkX2NvdW50X2RhdGFbLDM6bmNvbChub3JtYWxpemVkX2NvdW50X2RhdGEpXSksIDIsIGRlbnNpdHkpCiAgI2NhbGN1bGF0ZSB0aGUgbGltaXRzIGFjcm9zcyBhbGwgdGhlIHNhbXBsZXMKICAgIHhsaW0gPC0gMDsgeWxpbSA8LSAwCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgoY291bnRzX2RlbnNpdHkpKSB7CiAgICAgIHhsaW0gPC0gcmFuZ2UoYyh4bGltLCBjb3VudHNfZGVuc2l0eVtbaV1dJHgpKTsgCiAgICAgIHlsaW0gPC0gcmFuZ2UoYyh5bGltLCBjb3VudHNfZGVuc2l0eVtbaV1dJHkpKQogICAgfQogICAgY29scyA8LSByYWluYm93KGxlbmd0aChjb3VudHNfZGVuc2l0eSkpCiAgICBsdHlzIDwtIHJlcCgxLCBsZW5ndGgoY291bnRzX2RlbnNpdHkpKQogICAgI3Bsb3QgdGhlIGZpcnN0IGRlbnNpdHkgcGxvdCB0byBpbml0aWFsaXplIHRoZSBwbG90CiAgICBwbG90KGNvdW50c19kZW5zaXR5W1sxXV0sIHhsaW09eGxpbSwgeWxpbT15bGltLCB0eXBlPSJuIiwgCiAgICAgICAgIHlsYWI9IlNtb290aGluZyBkZW5zaXR5IG9mIGxvZzItQ1BNIixjZXgubGFiID0gMC44NSwgCiAgICAgICAgIG1haW4gPSAiRmlsdGVyZWQgYW5kIG5vcm1hbGl6ZWQgUk5BU2VxIFNhbXBsZXMgZGlzdHJpYnV0aW9uIikKICAgICNwbG90IGVhY2ggbGluZQogICAgZm9yIChpIGluIDE6bGVuZ3RoKGNvdW50c19kZW5zaXR5KSkgbGluZXMoY291bnRzX2RlbnNpdHlbW2ldXSwgY29sPWNvbHNbaV0sIGx0eT1sdHlzW2ldKQogICAgbGVnZW5kKCJ0b3ByaWdodCIsIGNvbG5hbWVzKGRhdGEycGxvdCksIGNvbD1jb2xzLCBsdHk9bHR5cywgY2V4PTAuNzUsIAogICAgICAgICAgIGJvcmRlciA9ImJsdWUiLCAgdGV4dC5jb2wgPSAiZ3JlZW40IiwgbWVyZ2UgPSBUUlVFLCBiZyA9ICJncmF5OTAiKQpgYGAKCiMjIFBBUlQgIzE6IGRpZmZlcmVudGlhbCBleHByZXNzaW9uIAoxLiBDYWxjdWxhdGUgcC12YWx1ZXMgZm9yIGVhY2ggb2YgdGhlIGdlbmVzIGluIHlvdXIgZXhwcmVzc2lvbiBzZXQuIEhvdyBtYW55IGdlbmVzIHdlcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQ/IFdoYXQgdGhyZXNob2xkcyBkaWQgeW91IHVzZSBhbmQgd2h5PwoqIFRoZXJlIGFyZSA3NDY0IGdlbmVzIHRoYXQgYXJlIGJlbG93IHRoZSBwLXZhbHVlLiBUaGUgdGhyZXNob2xkIEkgdXNlZCBpcyAwLjA1IGJlY2F1c2UgdGhpcyBpcyB3aGF0IHRoZSBhdXRob3JzIG9mIHRoZSBwYXBlciBzdWdndWVzdGVkIHRoYXQgdGhleSB1c2UuCjIuIE11bHRpcGxlIGh5cG90aGVzaXMgdGVzdGluZyAtIGNvcnJlY3QgeW91ciBwLXZhbHVlcyB1c2luZyBhIG11bHRpcGxlIGh5cG90aGVzaXMgY29ycmVjdGlvbiBtZXRob2QuIFdoaWNoIG1ldGhvZCBkaWQgeW91IHVzZT8gQW5kIFdoeT8gSG93IG1hbnkgZ2VuZXMgcGFzc2VkIGNvcnJlY3Rpb24/CiogSSB1c2VkIEZEUiBjb3JyZWN0aW9uIHdoaWNoIGlzIGFsc28gd2hhdCB0aGUgYXV0aG9ycyBvZiB0aGUgcGFwZXIgc3BlY2lmaWVkLiA1MDMzIGdlbmVzIHBhc3NlZCB0aGUgY29ycmVjdGlvbi4gQm90aCB0aGUgcC12YWx1ZSBhbmQgdGhlIGNvcnJlY3Rpb24gZGF0YSBhcmUgYmFzZWQgb24gdGhlIGVkZ2VSIHBhY2thZ2UsIG5vdCB0aGUgbGltbWEgcGFja2FnZS4gSSB1c2VkIHRoZSBsaW1tYSBwYWNrYWdlIHVwIHRpbGwgdGhlIHBvaW50IG9mIGNhbGN1bGF0aW5nIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGxpa2Ugd2hhdCBpcyBzdWdndWVzdGVkIG9uIHRoZSBsZWN0dXJlIG5vdGVzLgozLiBTaG93IHRoZSBhbW91bnQgb2YgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIHVzaW5nIGFuIE1BIFBsb3Qgb3IgYSBWb2xjYW5vIHBsb3QuIEhpZ2hsaWdodCBnZW5lcyBvZiBpbnRlcmVzdC4KKiBJIHNob3dlZCBhIHZvbGNhbm8gcGxvdCB1c2luZyBteSBlZGdlUiBmaXR0ZWQgZGF0YSBhbmQgaGlnaGxpZ2hlZCB0aGUgdXByZWd1bGF0ZWQgdG8gYmUgcmVkIGFuZCBkb3duIHJlZ3VsYXRlZCB0byBiZSBibHVlLgo0LiBWaXN1YWxpemUgeW91ciB0b3AgaGl0cyB1c2luZyBhIGhlYXRtYXAuIERvIHlvdSBjb25kaXRpb25zIGNsdXN0ZXIgdG9nZXRoZXI/IEV4cGxhaW4gd2h5IG9yIHdoeSBub3QuCiogTXkgZGF0YSBjbHVzdGVyZWQgcGVyZmVjdGx5IGFjY29yZGluZyB0byB0aGVpciBjZWxsIHR5cGVzIHdoaWNoIGlzIHdoYXQgbXkgbW9kZWwgZGVzaWduIGJhc2VkIG9uLiBNeSBpbnRlcnByZXRhdGlvbiBmb3IgdGhlIGdyYXBoIHdvdWxkIGJlIHRoYXQgc2luY2UgdGhlIGNvbG9ycyBhcmUgb3Bwb3NpdGUgdG8gZWFjaCBvdGhlciBpbiB0aGUgdHdvIGRpZmZlcmVudCBjZWxsIHR5cGVzLCBpdCBtZWFucyB0aGF0IHRoZSBnZW5lcyB0aGF0IGFyZSB1cHJlZ3VsYXRlZCBpbiB0dW1vdXJzcGhlcmUgd291bGQgYmUgZG93biByZWd1bGF0ZWQgaW4gcHJpbWFyeSB0dW1vdXIgc2FtcGxlcy4gVGhlIHNob3dzIGEgZ3JlYXQgcmVzdWx0cyB0aGF0IHRoZSB1cHJlZ3VsYXRlZCBnZW5lcyBjYW4gYmUgcG90ZW50aWFsIGJpb21hcmtlcnMgdG8gdHJhY2sgaWYgdHVtb3Vyc3BoZXJlIGlzIHByZXNlbnQgb3Igbm90LgoKIyMjIFNURVAgMTogQ2hvaWNlIG9mIGZhY3RvcnMgaW4gbXkgbW9kZWwKKiBJIGNyZWF0ZWQgdGhlIE1EUyBieSBib3RoIHVzaW5nICJjZWxsX3R5cGUiIGFuZCAiY2VsbF90eXBlIiBhbmQgInBhdGllbnQiLiBUaGUgY29tcGFyaXNvbiBiZXR3ZWVuIHRoZSB0d28gbW9kZWxzIGlzIGZhaXJseSBjbGVhcjogd2Ugc2hvdWxkIG9ubHkgZGVwZW5kIG9uIHRoZSBmYWN0b3IgImNlbGxfdHlwZSIsIHNpbmNlIHRoZXJlIHNlZW1zIHRvIGJlIG5vIGNvcnJlbGF0aW9uIHdpdGggZWFjaCBwYXRpZW50LgoKYGBge3IgTURTLTF9IApoZWF0bWFwX21hdHJpeCA8LSBub3JtYWxpemVkX2NvdW50X2RhdGFbLDM6bmNvbChub3JtYWxpemVkX2NvdW50X2RhdGEpXQpyb3duYW1lcyhoZWF0bWFwX21hdHJpeCkgPC0gbm9ybWFsaXplZF9jb3VudF9kYXRhJEdFTkVJRApjb2xuYW1lcyhoZWF0bWFwX21hdHJpeCkgPC0gcm93bmFtZXMoc2FtcGxlc19maWx0ZXJlZCkKCiMgTURTIHBsb3QgYnkgImNlbGxfdHlwZSIgaW4gc2FtcGxlcwpwbG90TURTKGhlYXRtYXBfbWF0cml4LCBsYWJlbHM9cm93bmFtZXMoc2FtcGxlc19maWx0ZXJlZCksIAogICAgICAgIGNvbCA9IGMoImRhcmtncmVlbiIsImJsdWUiKVtmYWN0b3Ioc2FtcGxlc19maWx0ZXJlZCRjZWxsX3R5cGUpXSwKICAgICAgICBtYWluID0gIk1EUyBwbG90IGRlcGVuZGluZyBvbiBjZWxsIHR5cGUiKQpgYGAKCgpgYGB7ciBNRFMtMn0gCnBhdF9jb2xvcnMgPC0gcmFpbmJvdygxMikKcGF0X2NvbG9ycyA8LSB1bmxpc3QobGFwcGx5KHBhdF9jb2xvcnMsRlVOPWZ1bmN0aW9uKHgpe3JlcCh4LDIpfSkpCiMgTURTIHBsb3QgYnkgImNlbGxfdHlwZSIgKyAicGF0aWVudHMiaW4gc2FtcGxlcwpwbG90TURTKGhlYXRtYXBfbWF0cml4LCBjb2wgPSBwYXRfY29sb3JzLAogICAgICAgIG1haW4gPSAiTURTIHBsb3QgZGVwZW5kaW5nIG9uIGJvdGggY2VsbCB0eXBlIGFuZCBwYXRpZW50cyIpCmBgYAoKIyMjIFNURVAgMjogRGVmaW5lIG15IG1vZGVsIGRlc2lnbgpCYXNlZCBvbiB0aGUgdHdvIG1vZGVscyBpbiBwYXJ0MSwgSSBkZWNpZGUgdG8gYmFzZSBteSBtb2RlbCBvbmx5IG9uICJjZWxsX3R5cGUiCmBgYHtyIG1vZGVsfSAKbW9kZWxfZGVzaWduIDwtIG1vZGVsLm1hdHJpeCh+IHNhbXBsZXMkY2VsbF90eXBlKQprYWJsZShtb2RlbF9kZXNpZ24sIHR5cGU9Imh0bWwiKQpgYGAKCiMjIyBTVEVQIDM6IENhbGN1bGF0ZSBwLXZhbHVlClRoZXJlIGFyZSA2OTg4IGdlbmVzIHRoYXQgcGFzcyB0aGUgcC12YWx1ZSA9IDAuMDUgd2hpY2ggaXMgY2hvc2VuIGJhc2VkIG9uIHRoZSBwYXBlci4KYGBge3IgcC12YWwsIHJlc3VsdHM9ImhpZGUifQpleHByZXNzaW9uTWF0cml4IDwtIGFzLm1hdHJpeChub3JtYWxpemVkX2NvdW50X2RhdGFbLDM6bmNvbChub3JtYWxpemVkX2NvdW50X2RhdGEpXSkKcm93bmFtZXMoZXhwcmVzc2lvbk1hdHJpeCkgPC0gbm9ybWFsaXplZF9jb3VudF9kYXRhJEdFTkVJRApjb2xuYW1lcyhleHByZXNzaW9uTWF0cml4KSA8LSBjb2xuYW1lcyhub3JtYWxpemVkX2NvdW50X2RhdGEpWzM6bmNvbChub3JtYWxpemVkX2NvdW50X2RhdGEpXQptaW5pbWFsU2V0IDwtIEV4cHJlc3Npb25TZXQoYXNzYXlEYXRhPWV4cHJlc3Npb25NYXRyaXgpCgojIGZpdApmaXQgPC0gbG1GaXQobWluaW1hbFNldCwgbW9kZWxfZGVzaWduKQoKIyBVc2UgQmF5ZXMKZml0MiA8LSBlQmF5ZXMoZml0LHRyZW5kPVRSVUUpCgojIENvcnJlY3Rpb246IEJIIChyZWNvbW1lbmRlZCBieSB0aGUgcGFwZXIpCnRvcGZpdCA8LSB0b3BUYWJsZShmaXQyLCBjb2VmPW5jb2wobW9kZWxfZGVzaWduKSwKICAgICAgICAgICAgICAgICAgIGFkanVzdC5tZXRob2QgPSAiQkgiLAogICAgICAgICAgICAgICAgICAgbnVtYmVyID0gbnJvdyhleHByZXNzaW9uTWF0cml4KSkKCiMgbWVyZ2UgZ2VuZSBzeW1ib2wgdG8gdG9wZml0IHRhYmxlCm91dHB1dF9oaXRzIDwtIG1lcmdlKG5vcm1hbGl6ZWRfY291bnRfZGF0YVssMToyXSwgdG9wZml0LCBieS55ID0gMCwgYnkueCA9IDEsIGFsbC55PVRSVUUpCgojc29ydGVkIGJ5IFAtdmFsdWUKb3V0cHV0X2hpdHMgPC0gb3V0cHV0X2hpdHNbb3JkZXIob3V0cHV0X2hpdHMkUC5WYWx1ZSksXQprYWJsZShvdXRwdXRfaGl0c1sxOjUsXSx0eXBlPSJodG1sIikKCiMgbnVtYmVyIG9mIGdlbmVzIHRoYXQgcGFzcyB0aHJlc2hvbGQgcC12YWx1ZSA9IDAuMDUKbGVuZ3RoKHdoaWNoKG91dHB1dF9oaXRzJFAuVmFsdWUgPCAwLjA1KSkgIyA2OTg4CgojIG51bWJlciBvZiBnZW5lcyB0aGF0IHBhc3MgY29ycmVjdGlvbgpsZW5ndGgod2hpY2gob3V0cHV0X2hpdHMkYWRqLlAuVmFsIDwgMC4wNSkpICMgNDA2MgpgYGAKCiMjIyBTVEVQIDQ6IFNldCB1cCBFZGdlUiBvYmplY3QKCmBgYHtyIGQgb2JqZWN0fQpkID0gREdFTGlzdChjb3VudHM9ZmlsdGVyZWRfZGF0YV9tYXRyaXgsIGdyb3VwPXNhbXBsZXMkY2VsbF90eXBlKQpkIDwtIGVzdGltYXRlRGlzcChkLCBtb2RlbF9kZXNpZ25fcGF0KQpgYGAKCiMjIyBTVEVQIDU6IFRlc3Qgd2hldGhlciBteSBkYXRhIGlzIHN1aXRhYmxlIGZvciBlZGdlUiAtIE1lYW5WYXIgcGxvdApJIGhhdmUgc2hvd24gdGhhdCBteSBkYXRhIGlzIHN1aXRhYmxlIGZvciB1c2luZyBlZGdlUiBmb3IgZnVydGhlciBhbmFseXNpcy4gVGhlIGRhdGEgZm9sbG93cyB0aGUgYmlub21pYWwgZGlzdHJpYnV0aW9uLgpgYGB7ciBtZWFudmFyfQpwbG90TWVhblZhcihkLCBzaG93LnJhdy52YXJzID0gVFJVRSwgICAgICAgICAgICAgICAgCiAgICAgICAgICAgIHNob3cudGFnd2lzZS52YXJzPVRSVUUsICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgc2hvdy5hdmUucmF3LnZhcnMgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICBOQmxpbmU9VFJVRSwKICAgICAgICAgICAgc2hvdy5iaW5uZWQuY29tbW9uLmRpc3AudmFycyA9IFRSVUUsCiAgICAgICAgICAgIG1haW4gPSAiQmlub21pYWwgZGlzdHJpYnV0aW9uIG9mIG15IGRhdGEiKQpgYGAKCiMjIyBTVEVQIDY6IEVzdGltYXRlIGRpc3BlcnNpb24gLSBCQ1YgcGxvdApUaGUgaW5kaXZpZHVhbCBkb3RzIHJlcHJlc2VudCBlYWNoIGdlbmUgYW5kIHRoZSBibHVlIGxpbmUgaXMgdGhlIG92ZXJhbGwgdHJlbmQgbGluZS4KYGBge3IgQkNWfQpwbG90QkNWKGQsY29sLnRhZ3dpc2UgPSAiYmxhY2siLGNvbC5jb21tb24gPSAicmVkIiwgCiAgICAgICAgbWFpbiA9ICJCQ1YgcGxvdCBvZiBSTkEtc2VxIGRhdGEiKQpgYGAKCiMjIyBTVEVQIDc6IEdlbmVzIHBhc3MgdGhyZXNob2xkIGFuZCBGRFIgY29ycmVjdGlvbiAKCkkgdXNlZCBRdWFzaS1saWtlbGlob29kIG1vZGVscyB0byBmaXQgbXkgZGF0YSBhbmQgdXNlZCBRTEZUZXN0IHRvIHRlc3QgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uLiBUaGUgUXVhc2ktbGlrZWxpaG9vZCBjb21wYXJlcyB0d28gY29uZGl0aW9ucyAocHJpbWFyeSB0dW1vdXIgYW5kIHR1bW91cnNwaGVyZSkgYW5kIHNob3dzIHRoZSB1cCBhbmQgZG93bi1yZWd1bGF0ZWQgZ2VuZXMuIFRoZSByZXN1bHQgYmVsb3cgdGhhdCBhcmUgc29ydGVkIGJ5IHAtdmFsdWUuIEkgYWxzbyBpbnNwZWN0ZWQgdGhlIG51bWJlciBvZiBnZW5lcyB0aGF0IHNhdGlzdHkgbXkgdGhyZXNob2xkIGFuZCBjb3JyZWN0aW9uLiBJIGNob29zZSB0byB1c2UgRkRSIGNvcnJlY3Rpb24gYmFzZWQgb24gdGhlIHBhcGVyIGFzIHdlbGxbQGdvaDIwMTdjaHJvbW9zb21lXSAuIFRoZXJlIGFyZSA3NDY3IGdlbmVzIHBhc3MgdGhlIHAtdmFsdWUgPSAwLjA1LCBhbmQgNTAzMyBnZW5lcyB0aGF0IHBhc3MgdGhlIEZEUiBjb3JyZWN0aW9uLgpgYGB7ciB0aHJlc2hvbGQgYW5kIGNvcnJlY3Rpb24sIHJlc3VsdHMgPSAiaGlkZSJ9CmZpdCA8LSBnbG1RTEZpdChkLCBtb2RlbF9kZXNpZ24pCnFsZi5zcGhlcmVfdnNfdHVtb3VyIDwtIGdsbVFMRlRlc3QoZml0LCBjb2VmPSdzYW1wbGVzJGNlbGxfdHlwZVNwaGVyZScpCmthYmxlKHRvcFRhZ3MocWxmLnNwaGVyZV92c190dW1vdXIpLCB0eXBlPSJodG1sIikKCiMgR2V0IGFsbCB0aGUgcmVzdWx0cwpxbGZfb3V0cHV0X2hpdHMgPC0gdG9wVGFncyhxbGYuc3BoZXJlX3ZzX3R1bW91ciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvcnQuYnkgPSAiUFZhbHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG4gPSBucm93KG5vcm1hbGl6ZWRfY291bnRfZGF0YSkpCgojIE51bWJlciBvZiBnZW5lcyB0aGF0IHBhc3MgdGhlIHRocmVzaG9sZCBwLXZhbHVlID0gMC4wNQpsZW5ndGgod2hpY2gocWxmX291dHB1dF9oaXRzJHRhYmxlJFBWYWx1ZSA8IDAuMDUpKSAjIDc0NjcKCiMgTnVtYmVyIG9mIGdlbmVzIHRoYXQgcGFzcyBjb3JyZWN0aW9uCmxlbmd0aCh3aGljaChxbGZfb3V0cHV0X2hpdHMkdGFibGUkRkRSIDwgMC4wNSkpICMgNTAzMwpgYGAKCiMjIyBTVEVQIDg6IFVwIGFuZCBkb3duLXJlZ3VsYXRlZCBnZW5lcwoKSSBkZXRlcm1pbmVkIHRoZSBudW1iZXIgb2YgdXAtcmVndWxhdGVkIGdlbmVzIGJ5IHNlbGVjdGluZyBldmVyeSBnZW5lIHRoYXQgZG9lcyBub3QgcGFzcyBteSBwLXZhbHVlOiAwLjA1LCBhbmQgYWxzbyBoYXZlIGEgcG9zaXRpdmUgbG9nIGZvbGQgY2hhbmdlLiBEb3duLXJlZ3VsYXRlZCBnZW5lcyBhcmUgc2VsZWN0ZWQgaW4gdGhlIHNhbWUgd2F5IHdpdGggYSBuZWdhdGl2ZSBsb2cgZm9sZCBjaGFuZ2UuIFN0b3JlZCB0aGVzZSBkYXRhIGZvciBsYXRlciBlbnJpY2htZW50IGFuYWx5c2lzIG9uIGdQcm9maWxlUi4gCgpgYGB7ciB1cCBhbmQgZG93bi1yZWd1bGF0ZWQsIHJlc3VsdHM9ImhpZGUifQojIG51bWJlciBvZiBnZW5lcyB0aGF0IGFyZSB1cCByZWd1bGF0ZWQKbGVuZ3RoKHdoaWNoKHFsZl9vdXRwdXRfaGl0cyR0YWJsZSRQVmFsdWUgPCAwLjA1IAogICAgICAgICAgICAgJiBxbGZfb3V0cHV0X2hpdHMkdGFibGUkbG9nRkMgPiAwKSkgIyAxODk3CgojIG51bWJlciBvZiBnZW5lcyB0aGF0IGFyZSBkb3duIHJlZ3VsYXRlZApsZW5ndGgod2hpY2gocWxmX291dHB1dF9oaXRzJHRhYmxlJFBWYWx1ZSA8IDAuMDUgIAogICAgICAgICAgICAgJiBxbGZfb3V0cHV0X2hpdHMkdGFibGUkbG9nRkMgPCAwKSkgIyA1NTcwCgojIEdldCB0aG9zZSB1cCBhbmQgZG93bi1yZWd1bGF0ZWQgZ2VuZXMKcWxmX291dHB1dF9oaXRzX3dpdGhnbiA8LSBtZXJnZShleHByX2ZpbHRlcmVkWywxOjJdLHFsZl9vdXRwdXRfaGl0cywgYnkueD0xLCBieS55ID0gMCkKCnVwcmVndWxhdGVkX2dlbmVzIDwtIHFsZl9vdXRwdXRfaGl0c193aXRoZ24kR0VORUlEW3doaWNoKHFsZl9vdXRwdXRfaGl0cyR0YWJsZSRQVmFsdWUgPCAwLjA1IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmIHFsZl9vdXRwdXRfaGl0cyR0YWJsZSRsb2dGQyA+IDApXQoKZG93bnJlZ3VsYXRlZF9nZW5lcyA8LXFsZl9vdXRwdXRfaGl0c193aXRoZ24kR0VORUlEW3doaWNoKHFsZl9vdXRwdXRfaGl0cyR0YWJsZSRQVmFsdWUgPCAwLjA1IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYgcWxmX291dHB1dF9oaXRzJHRhYmxlJGxvZ0ZDIDwgMCldCgoKIyBzdG9yZSBkYXRhIC0gYWxsIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZAp1bnJlZ19nZW5lc19jb3B5IDwtIGRhdGEuZnJhbWUodXByZWd1bGF0ZWRfZ2VuZXMpCmRvd25yZWdfZ2VuZXNfY29weSA8LSBkYXRhLmZyYW1lKGRvd25yZWd1bGF0ZWRfZ2VuZXMpCm5hbWVzKHVucmVnX2dlbmVzX2NvcHkpIDwtIG5hbWVzKGRvd25yZWdfZ2VuZXNfY29weSkKYWxsX2RlIDwtIHJiaW5kKHVucmVnX2dlbmVzX2NvcHksIGRvd25yZWdfZ2VuZXNfY29weSkKY29sbmFtZXMoYWxsX2RlKSA8LSAiYWxsX2RlIgp3cml0ZS50YWJsZSh4PWFsbF9kZSwKICAgICAgICAgICAgZmlsZT0iYWxsX2V4cHJfZGVfZ2VuZXMudHh0IixzZXAgPSAiXHQiLAogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSxjb2wubmFtZXMgPSBGQUxTRSxxdW90ZSA9IEZBTFNFKQoKIyB1cCByZWd1bGF0ZWQKd3JpdGUudGFibGUoeD11cHJlZ3VsYXRlZF9nZW5lcywKICAgICAgICAgICAgZmlsZT0iZXhwcl91cHJlZ3VsYXRlZF9nZW5lcy50eHQiLHNlcCA9ICJcdCIsCiAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLGNvbC5uYW1lcyA9IEZBTFNFLHF1b3RlID0gRkFMU0UpCgojIGRvd24gcmVndWxhdGVkCndyaXRlLnRhYmxlKHg9ZG93bnJlZ3VsYXRlZF9nZW5lcywKICAgICAgICAgICAgZmlsZT0iZXhwcl9kb3ducmVndWxhdGVkX2dlbmVzLnR4dCIsc2VwID0gIlx0IiwKICAgICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UsY29sLm5hbWVzID0gRkFMU0UscXVvdGUgPSBGQUxTRSkKYGBgCgojIyMgU1RFUCA5OiBTaG93IHVwIGFuZCBkb3duLXJlZ3VsYXRlZCBnZW5lcwoKSSBoYXZlIHNob3duIHRoZSB1cCBhbmQgZG93bi1yZWd1bGF0ZWQgZ2VuZXMgaW4gYSB2b2xjYW5vIHBsb3QgYnkgY29sb3JpbmcgdGhlbSBpbiByZWQgYW5kIGJsdWUsIHRoZSBjb2RlIGlzIGZyb20gW0B0b21hdG9kYXRhMjAxN10KYGBge3IgdXBfdm9sY2Fub30Kdm9sY2Fub0RhdGEgPC0gY2JpbmQocWxmX291dHB1dF9oaXRzJHRhYmxlJGxvZ0ZDLCAtbG9nMTAocWxmX291dHB1dF9oaXRzJHRhYmxlJEZEUikpCmNvbG5hbWVzKHZvbGNhbm9EYXRhKSA8LSBjKCJsb2dGQyIsICJQdmFsIikKCnVwIDwtIHFsZl9vdXRwdXRfaGl0cyR0YWJsZSRGRFIgPCAwLjA1ICYgcWxmX291dHB1dF9oaXRzJHRhYmxlJGxvZ0ZDID4gMApwb2ludC5jb2wgPC0gaWZlbHNlKHVwLCAicmVkIiwgImJsYWNrIikKcGxvdCh2b2xjYW5vRGF0YSwgcGNoID0gMTYsIGNvbCA9IHBvaW50LmNvbCwgY2V4ID0gMC41LAogICAgIG1haW4gPSAiVXAtcmVndWxhdGVkIGdlbmVzIGluIFJOQS1zZXEgZGF0YSIpCmBgYAoKYGBge3IgZG93bl92b2xjYW5vfQpkb3duIDwtIHFsZl9vdXRwdXRfaGl0cyR0YWJsZSRGRFIgPCAwLjA1ICYgcWxmX291dHB1dF9oaXRzJHRhYmxlJGxvZ0ZDIDwgMApwb2ludC5jb2wgPC0gaWZlbHNlKGRvd24sICJibHVlIiwgImJsYWNrIikKcGxvdCh2b2xjYW5vRGF0YSwgcGNoID0gMTYsIGNvbCA9IHBvaW50LmNvbCwgY2V4ID0gMC41LAogICAgICBtYWluID0gIkRvd24tcmVndWxhdGVkIGdlbmVzIGluIFJOQS1zZXEgZGF0YSIpCmBgYAoKCiMjIyBTVEVQIDEwOiBUZXN0IERpZmZlcmVudGlhbCBleHByZXNzaW9uIC0gaGVhdG1hcAoKVG8gdGVzdCB0aGUgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24sIEkgdXNlZCB0aGUgaGVhdG1hcCBhbmQgaXQgaGFzIHNob3duIGEgY2xlYXIgZGlzdGluY3Rpb24gYmV0d2VlbiB1cCBhbmQgZG93biByZWd1bGF0ZWQgZ2VuZXMuIFRoZXJlIGlzIGEgY2xlYXIgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBwcmltYXJ5IHR1bW91ciBzYW1wbGVzIGFuZCB0dW1vdXJzcGhlcmUgc2FtcGxlcy4oVGhleSBhcmUgcmV2ZXJzZWQuKSBUaGUgY2x1c3RlcmluZyBpcyB2ZXJ5IG9idmlvdXMgdG8gc2hvdyB0aGF0IGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGV4aXN0cy4KCmBgYHtyIGhlYXRtYXB9CnRvcF9oaXRzIDwtIHJvd25hbWVzKHFsZl9vdXRwdXRfaGl0cyR0YWJsZSlbb3V0cHV0X2hpdHMkUC5WYWx1ZTwwLjA1XSAKaGVhdG1hcF9tYXRyaXhfdG9waGl0cyA8LSB0KHNjYWxlKHQoaGVhdG1hcF9tYXRyaXhbd2hpY2gocm93bmFtZXMoaGVhdG1hcF9tYXRyaXgpICVpbiUgdG9wX2hpdHMpLF0pKSkgCmhlYXRtYXBfbWF0cml4X3RvcGhpdHMgPC0gaGVhdG1hcF9tYXRyaXhfdG9waGl0c1ssIGMoZ3JlcChjb2xuYW1lcyhoZWF0bWFwX21hdHJpeF90b3BoaXRzKSxwYXR0ZXJuID0gIl9QIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcChjb2xuYW1lcyhoZWF0bWFwX21hdHJpeF90b3BoaXRzKSxwYXR0ZXJuID0gIl9TIikpXQoKaWYobWluKGhlYXRtYXBfbWF0cml4X3RvcGhpdHMpID09IDApewogICAgaGVhdG1hcF9jb2wgPSBjb2xvclJhbXAyKGMoIDAsIG1heChoZWF0bWFwX21hdHJpeF90b3BoaXRzKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoICJ3aGl0ZSIsICJyZWQiKSkKICAgIH0gZWxzZSB7CiAgICBoZWF0bWFwX2NvbCA9IGNvbG9yUmFtcDIoYyhtaW4oaGVhdG1hcF9tYXRyaXhfdG9waGl0cyksIDAsIG1heChoZWF0bWFwX21hdHJpeF90b3BoaXRzKSksIGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpCiAgICB9CgpjdXJyZW50X2hlYXRtYXAgPC0gSGVhdG1hcChhcy5tYXRyaXgoaGVhdG1hcF9tYXRyaXhfdG9waGl0cyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19yb3dfZGVuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2w9aGVhdG1hcF9jb2wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfaGVhdG1hcF9sZWdlbmQgPSBUUlVFLCkKY3VycmVudF9oZWF0bWFwCmBgYAoKIyMgUEFSVCAyOiBUaHJlc2hvbGRlZCBvdmVyLXJlcHJlc2VudGF0aW9uIGFuYWx5c2lzCiMjIyBJbnRyb2R1Y3Rpb24gdG8gUEFSVCAyOgoxLiAqV2hpY2ggbWV0aG9kIGRpZCB5b3UgY2hvb3NlIGFuZCB3aHk/KgoqIEkgY2hvc2UgdG8gdXNlIGc6cHJvZmlsZXIgYmVjYXVzZSBpdCBzaG93cyBtZSB0aGUgdG9wIHRlcm0gbmFtZXMgaW4gS0VHRywgV1AsIEdPIGFuZCBSRUFDLCB3aGljaCBpcyBoZWxwZnVsIGZvciBtZSB3aGVuIGRlY2lkaW5nIHdoYXQgdHlwZSBvZiBkaXNlYXNlIGl0IGlzIG1vc3QgbGlrZWx5IHRvIGJlLgoyLiAqV2hhdCBhbm5vdGF0aW9uIGRhdGEgZGlkIHlvdSB1c2UgYW5kIHdoeT8gV2hhdCB2ZXJzaW9uIG9mIHRoZSBhbm5vdGF0aW9uIGFyZSB5b3UgdXNpbmc/KgoqIEdPIGJpb2xvZ2ljYWwgcHJvY2VzczogIHJlbGVhc2VzLzIwMTktMDctMDEKKiBLRUdHOiBLRUdHIEZUUCBSZWxlYXNlIDIwMTktMDktMzAKKiBSZWFjdG9tZTogZW5zZW1ibCBjbGFzc2VzOiAyMDE5LTEwLTIKKiBXaWtpUGF0aHdheXM6IDIwMTkwOTEwCjMuICpIb3cgbWFueSBnZW5lc2V0cyB3ZXJlIHJldHVybmVkIHdpdGggd2hhdCB0aHJlc2hvbGRzPyoKKiBUaGUgdGhyZXNob2xkIGZvciBhbGwgdGhlIHF1ZXJpZXM6IDAuMDUKKiA4MjEgZ2VuZSBzZXRzIGFyZSByZXR1cm5lZCBmb3IgYWxsIHRoZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMuCiogNjAgZ2VuZSBzZXRzIGFyZSByZXR1cm5lZCBmb3IgdXAtcmVndWxhdGVkIGdlbmVzLgoqIDEzMzMgZ2VuZSBzZXRzIGFyZSByZXR1cm5lZCBmb3IgZG93bi1yZWd1bGF0ZWQgZ2VuZXMuCgo0LiBSdW4gdGhlIGFuYWx5c2lzIHVzaW5nIHRoZSB1cC1yZWd1bGF0ZWQgc2V0IG9mIGdlbmVzLCBhbmQgdGhlIGRvd24tcmVndWxhdGVkIHNldCBvZiBnZW5lcyBzZXBhcmF0ZWx5LiBIb3cgZG8gdGhlc2UgcmVzdWx0cyBjb21wYXJlIHRvIHVzaW5nIHRoZSB3aG9sZSBsaXN0IChpLmUgYWxsIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyB0b2dldGhlciB2cy4gdGhlIHVwLXJlZ3VsYXRlZCBhbmQgZG93biByZWd1bGF0ZWQgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIHNlcGFyYXRlbHkpPwoqIFRoZSB1cC1yZWd1bGF0ZWQgZ2VuZSBzZXRzIGFyZSBtb3N0bHkgY2VsbHVsYXIgcHJvY2Vzc2VzIGFuZCBtZXRhYm9saWMgcHJvY2Vzc2VzLgoqIFRoZSB0b3AgdGVybXMgZm9yIGRvd24tcmVndWxhdGVkIGdlbmUgc2V0cyBhcmUgbW9zdGx5IHNpZ25hbGluZyBwYXRod2F5cyBhbmQgbWV0YWJvbGljIHByb2Nlc3Nlcy8KKiBXaGVuIHJ1bm5pbmcgd2l0aCBib3RoIHVwIGFuZCBkb3duLXJlZ3VsYXRlZCBnZW5lcywgSSBmb3VuZCB0aGF0IG1vc3Qgb2YgdGhlbSBhcmUgZG9taW5hdGVkIGJ5IHRoZSBtZXRhYm9saWMgYW5kIGNlbGx1bGFyIHByb2Nlc3NlcyAodXAgcmVndWxhdGVkIHRvcCB0ZXJtcykuIFRoZXJlZm9yZSwgaXQgY29udmluY2VzIG1lIHRoZSBpbXBvcnRhbmNlIG9mIHRoZSB1cC1yZWd1bGF0ZWQgZ2VuZXMgaW4gdGhlIGNhbmNlci4gQW5kIHRoZSByZXN1bHQgYWxpZ25zIHdpdGggdGhlIHBhcGVyIHRoYXQgc3RhdGVzIHRoZSBjYW5jZXIgaXMgb2Ygc3VidHlwZSAiYmFzYWwiLgoqIEJlbG93IGFyZSBteSByZXN1bHRzIGZvciBlYWNoIHVwLXJlZ3VsYXRlZCwgZG93bi1yZWd1bGF0ZWQsIGFuZCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgKGJvdGgpLgoKIyMjIFVwIHJlZ3VsYXRlZCBnZW5lcwpUaGVyZSB3ZXJlIG5vIFJFQUMgZm91bmQuIEkgdXNlZCB0aGUgZ3Byb2ZpbGVyMidzIGZ1bmN0aW9uIHRvIHF1ZXJ5IGRhdGEgYW5kIGFsc28gYXR0YWNoZWQgdGhlIHNjcmVlbnNob3RzIHRoYXQgSSB0b29rIG9uIHRoZWlyIHdlYnNpdGUgc2luY2UgdGhlIHBhY2thZ2UgZG9lcyBub3Qgc2hvdyB0aGUgbnVtYmVyIG9mIGdlbmUgc2V0cyBlYWNoIGhhcyBmb3VuZC4gCmBgYHtyIFVwIHJlZ3VsYXRlZCBnZW5lc30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIi9Vc2Vycy9oZWxlbmRpbmcvRG9jdW1lbnRzL0JDQjQyMC9waWNzL2FsbF91cC5wbmciKQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL1VzZXJzL2hlbGVuZGluZy9Eb2N1bWVudHMvQkNCNDIwL3BpY3MvS0VHR191cC5wbmciKQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL1VzZXJzL2hlbGVuZGluZy9Eb2N1bWVudHMvQkNCNDIwL3BpY3MvV1BfdXAucG5nIikKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIi9Vc2Vycy9oZWxlbmRpbmcvRG9jdW1lbnRzL0JDQjQyMC9waWNzL0dPX3VwLnBuZyIpCgpncHJvX3VwcmVndWxhdGVkIDwtIGdwcm9maWxlcjI6Omdvc3QodXByZWd1bGF0ZWRfZ2VuZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAiaHNhcGllbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWRfcXVlcnkgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpX3F1ZXJ5ID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmlmaWNhbnQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2x1ZGVfaWVhID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFzdXJlX3VuZGVycmVwcmVzZW50YXRpb24gPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyX3RocmVzaG9sZCA9IDAuMDUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVjdGlvbl9tZXRob2QgPSBjKCJmZHIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbWFpbl9zY29wZSA9IGMoImFubm90YXRlZCIsICJrbm93biIsICJjdXN0b20iLCAiY3VzdG9tX2Fubm90YXRlZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VzdG9tX2JnID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1lcmljX25zID0gIiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlcyA9IGMoIkdPOkJQIiwgIktFR0ciLCAiUkVBQyIsICJXUCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfc2hvcnRfbGluayA9IEZBTFNFKQoKZ3Byb2ZpbGVyMjo6Z29zdHBsb3QoZ3Byb191cHJlZ3VsYXRlZCwgCiAgICAgICAgICAgICAgICAgICAgIGNhcHBlZCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZSA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICBwYWwgPSBjKGBHTzpCUGAgPSAiI2ZmOTkwMCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEtFR0cgPSAiI2RkNDQ3NyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUkVBQyA9ICIjMzM2NmNjIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV1AgPSAiIzAwOTljNiIpKQpgYGAKCiMjIyBEb3duIHJlZ3VsYXRlZCBnZW5lcwoKVGhlIHNvbWUgYW5hbHlzaXMgaXMgYXBwbHkgdG8gZG93biByZWd1bGF0ZWQKYGBge3IgRG93biByZWd1bGF0ZWQgZ2VuZXN9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIvVXNlcnMvaGVsZW5kaW5nL0RvY3VtZW50cy9CQ0I0MjAvcGljcy9hbGxfZG93bi5wbmciKQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL1VzZXJzL2hlbGVuZGluZy9Eb2N1bWVudHMvQkNCNDIwL3BpY3MvS0VHR19kb3duLnBuZyIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIvVXNlcnMvaGVsZW5kaW5nL0RvY3VtZW50cy9CQ0I0MjAvcGljcy9XUF9kb3duLnBuZyIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIvVXNlcnMvaGVsZW5kaW5nL0RvY3VtZW50cy9CQ0I0MjAvcGljcy9HT19kb3duLnBuZyIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIvVXNlcnMvaGVsZW5kaW5nL0RvY3VtZW50cy9CQ0I0MjAvcGljcy9SRUFDX2Rvd24ucG5nIikKCmdwcm9fZG93bnJlZ3VsYXRlZCA8LSBncHJvZmlsZXIyOjpnb3N0KGRvd25yZWd1bGF0ZWRfZ2VuZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAiaHNhcGllbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWRfcXVlcnkgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpX3F1ZXJ5ID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmlmaWNhbnQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2x1ZGVfaWVhID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFzdXJlX3VuZGVycmVwcmVzZW50YXRpb24gPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyX3RocmVzaG9sZCA9IDAuMDUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVjdGlvbl9tZXRob2QgPSBjKCJmZHIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbWFpbl9zY29wZSA9IGMoImFubm90YXRlZCIsICJrbm93biIsICJjdXN0b20iLCAiY3VzdG9tX2Fubm90YXRlZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VzdG9tX2JnID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1lcmljX25zID0gIiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlcyA9IGMoIkdPOkJQIiwgIktFR0ciLCAiUkVBQyIsICJXUCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfc2hvcnRfbGluayA9IEZBTFNFKQpncHJvZmlsZXIyOjpnb3N0cGxvdChncHJvX2Rvd25yZWd1bGF0ZWQsIAogICAgICAgICAgICAgICAgICAgICBjYXBwZWQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmUgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgcGFsID0gYyhgR086QlBgID0gIiNmZjk5MDAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBLRUdHID0gIiNkZDQ0NzciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJFQUMgPSAiIzMzNjZjYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdQID0gIiMwMDk5YzYiKSkKYGBgCgojIyMgQWxsIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcwpgYGB7ciBBbGwgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL1VzZXJzL2hlbGVuZGluZy9Eb2N1bWVudHMvQkNCNDIwL3BpY3MvYWxsX0RFLnBuZyIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIvVXNlcnMvaGVsZW5kaW5nL0RvY3VtZW50cy9CQ0I0MjAvcGljcy9LRUdHX0RFLnBuZyIpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIvVXNlcnMvaGVsZW5kaW5nL0RvY3VtZW50cy9CQ0I0MjAvcGljcy9XUF9ERS5wbmciKQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL1VzZXJzL2hlbGVuZGluZy9Eb2N1bWVudHMvQkNCNDIwL3BpY3MvR09fREUucG5nIikKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIi9Vc2Vycy9oZWxlbmRpbmcvRG9jdW1lbnRzL0JDQjQyMC9waWNzL1JFQUNfREUucG5nIikKYWxsX2RlIDwtIHJlYWQudGFibGUoImFsbF9leHByX2RlX2dlbmVzLnR4dCIpCmdwcm9fYWxsX2RlIDwtIGdwcm9maWxlcjI6Omdvc3QoYWxsX2RlWywxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gImhzYXBpZW5zIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdWx0aV9xdWVyeSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25pZmljYW50ID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNsdWRlX2llYSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZV91bmRlcnJlcHJlc2VudGF0aW9uID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZjb2RlcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlcl90aHJlc2hvbGQgPSAwLjA1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlY3Rpb25fbWV0aG9kID0gYygiZmRyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb21haW5fc2NvcGUgPSBjKCJhbm5vdGF0ZWQiLCAia25vd24iLCAiY3VzdG9tIiwgImN1c3RvbV9hbm5vdGF0ZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1c3RvbV9iZyA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtZXJpY19ucyA9ICIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZXMgPSBjKCJHTzpCUCIsICJLRUdHIiwgIlJFQUMiLCAiV1AiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzX3Nob3J0X2xpbmsgPSBGQUxTRSkKZ3Byb2ZpbGVyMjo6Z29zdHBsb3QoZ3Byb19hbGxfZGUsIAogICAgICAgICAgICAgICAgICAgICBjYXBwZWQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmUgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgcGFsID0gYyhgR086QlBgID0gIiNmZjk5MDAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBLRUdHID0gIiNkZDQ0NzciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJFQUMgPSAiIzMzNjZjYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdQID0gIiMwMDk5YzYiKSkKYGBgCgojIEludGVycHJldGF0aW9uIHF1ZXN0aW9ucwoxLiBEbyB0aGUgb3Zlci1yZXByZXNlbnRhdGlvbiByZXN1bHRzIHN1cHBvcnQgY29uY2x1c2lvbnMgb3IgbWVjaGFuaXNtIGRpc2N1c3NlZCBpbiB0aGUgb3JpZ2luYWwgcGFwZXI/CiogVGhlIHBhcGVyIGZvdW5kIDE0MDEgZ2VuZXMgYmVpbmcgdXAtcmVndWxhdGVkIHdpdGggZm9sZCBjaGFuZ2UgPiAyIGFuZCBGRFIgPCAwLjA1LiBJIGZvdW5kIDEzMTIgd2hpY2ggaXMgcm91Z2hseSBzaW1pbGFyLiBUaGV5IGFsc28gZm91bmQgdGhhdCBBTERIIGZhbWlseSBpcyB1cC1yZWd1bGF0ZWQgYXMgd2VsbC4gQnV0IEkgZm91bmQgMyBvZiB0aGVtIGluIG15IHVwcmVndWxhdGVkIGdlbmVzLiBUaGUgZGlzZWFzZSBpcyBpbmRpY2F0ZWQgYXMgMzElIG9mIGJhc2FsLWxpa2UgdHVtb3JzLCAxMiUgKEhFUjIpKyB0dW1vcnMgYW5kIDEwJSBvZiBsdW1pbmFsIHR1bW9ycywgc2luY2UgdGhlIHRvcCB0ZXJtcyBvZiBteSB1cHJlZ3VsYXRlZCBnZW5lcyBhcmUgbWV0YWJvbGljIHByb2Nlc3NlcywgdGhlcmVmb3JlLCB0aGUgcmVzdWx0IGFsaWducyB3aXRoIHRoZSBwYXBlci4KKiBUaGUgcGFwZXIgZGlkIG5vdCBtZW50aW9uIGFib3V0IHRoZSBkb3duLXJlZ3VsYXRlZCBnZW5lcy4KYGBge3IgaW50ZXJwcmV0YXRpbiBxdWVzdGlvbnMsIHJlc3VsdHM9ImhpZGUifQp1cHJlZ3VsYXRlZF9nZW5lc19zeW0gPC0gcWxmX291dHB1dF9oaXRzX3dpdGhnbiRTWU1CT0xbd2hpY2gocWxmX291dHB1dF9oaXRzJHRhYmxlJFBWYWx1ZSA8IDAuMDUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYgcWxmX291dHB1dF9oaXRzJHRhYmxlJGxvZ0ZDID4gMSldCgpsZW5ndGgodXByZWd1bGF0ZWRfZ2VuZXNfc3ltKSAjIDEzMTIKCgp1cHJlZ3VsYXRlZF9nZW5lc19zeW1bZ3JlcChwYXR0ZXJuPSJBTERIIix1cHJlZ3VsYXRlZF9nZW5lc19zeW0pXQojIEFMREgyLCBBTERIOEExLCBBTERIMUwyIC0+IGNvbmZpcm1lZCEKYGBgCgoyLiBFdmlkZW5jZSB0aGF0IHN1cHBvcnQgYW5kIGhvdyB0aGV5IHN1cHBvcnQgeW91ciByZXN1bHRzLgoKKiBNeSByZXN1bHQgIzE6IEFMREggZmFtaWx5IGlzIGZvdW5kIGluIG15IHVwIHJlZ3VsYXRlZCBnZW5lcy4KVmVyaWZpY2F0aW9uIG9mIG92ZXItcmVwcmVzZW50YXRpb24gb2YgQUxESCBpcyBhbiBpbXBvcnRhbnQgZmFtaWx5IGluIGJyZWFzdCBjYW5jZXIgYnkgW0B2YXNzYWxsaTIwMTlhbGRlaHlkZV0uIFRoZXkgY29uc2lkZXIgQUxESCBmYW1pbHkgYXMgYSBiaW9tYXJrZXIgZm9yIGJyZWFzdCBjYW5jZXIgd2hpY2ggc3VnZ3Vlc3RzIHRoYXQgbXkgcmVzdWx0ICh0aGUgZmFjdCB0aGF0IHVwLXJlZ3VsYXRlZCBnZW5lcyBjb250YWlucyB0aGUgQUxESCBmYW1pbHkgaXMgdmVyaWZpZWQpLiAKKiBNeSByZXN1bHQgIzI6IHRvcCB0ZXJtcyBvZiB0aGUgdXByZWd1bGF0ZWQgZ2VuZXMgYXJlIG1vc3RseSBjZWxsdWxhciBhbmQgbWV0YWJvbGljIHByb2Nlc3Nlcy4KW0B2YXNpbGlvdTIwMDVhbmFseXNpc10gY29udmluY2VzIG1lIHRoYXQgbXkgcmVzdWx0IGZyb20gZzpwcm9maWxlciBtYXRjaGVzIHdpdGggdGhlIGJhc2FsIHN1YnR5cGUuIFRoZSBwYXBlciBzdGF0ZXMgdGhhdCBtdXRhdGlvbnMgaW4gQUxESCBnZW5lcyBjYXVzZXMgbWV0YWJvbGlzbSBlcnJvcnMsIGZvciBleGFtcGxlLCBTasO2Z3JlbiAtIExhcnNzb24gc3luZHJvbWUsIHR5cGUgSUkgaHlwZXJwcm9saW5hZW1pYSBhbmQgzrMtaHlkcm94eWJ1dHlyaWMgYWNpZHVyaWEgYW5kIGV2ZW4gY2FuY2VyIGFuZCBBbHpoZWltZXIncyBkaXNlYXNlLiAKCiMgUmVmZXJlbmNlcw==